#include "MemoryManagementUnit.h"

MemoryManagementUnit::MemoryManagementUnit(int numOfPRocesses, int numOfKernelPages, int numOfEnteries, int pageSize, Memory* MM)
{
	userMiss = 0;
	userTotal = 0;
	kernelMiss = 0;
	kernelTotal = 0;

	m_outerTables = new map<int, int*>();
	m_numOfPRocesses = numOfPRocesses;
	m_numOfKernelPages = numOfKernelPages;
	m_numOfEnteries = numOfEnteries;
	m_pageSize = pageSize;
	m_MM = MM;
}

MemoryManagementUnit::~MemoryManagementUnit(void)
{
	delete m_outerTables;
}

void MemoryManagementUnit::addProcess(int pid)
{
	(*m_outerTables)[pid] = new int[m_numOfKernelPages];
	for(int i=0 ; i<m_numOfKernelPages ; i++)
	{
		(*m_outerTables)[pid][i] = PAGE_FAULT;
	}
}

bool MemoryManagementUnit::freePage(int pageNum, int pid)
{
	int* outerTable = (*m_outerTables)[pid];
	if(outerTable[pageNum] == PAGE_FAULT) return false;
	else
	{
		for(int j=0 ; j<m_numOfEnteries ;j++)
		{
			int userPageNum = *(int*)m_MM->read(KERNEL, outerTable[pageNum],j*4, 0);
			if(userPageNum != PAGE_FAULT)
			{
				m_MM->free(userPageNum,USER);
			}
		}
		m_MM->free(outerTable[pageNum],KERNEL);
		return true;
	}
}


void MemoryManagementUnit::deleteProcess(int pid)
{
	delete (*m_outerTables)[pid];
}

void MemoryManagementUnit::contextSwitch(int pid)
{
	m_currOuterTable = (*m_outerTables)[pid];
}

int MemoryManagementUnit::getPage(int vAddr, int pTime)
{
	int userPageNum = vAddr/m_pageSize;
	int kernelPageNum = userPageNum/m_numOfEnteries;
	kernelTotal++;
	if(m_currOuterTable[kernelPageNum] == PAGE_FAULT)
	{
		RequestedPage = kernelPageNum;
		RequestDomain = KERNEL;
		kernelMiss++;
		return PAGE_FAULT;
	}
	userTotal++;
	userPageNum = *(int*)m_MM->read(KERNEL, m_currOuterTable[kernelPageNum],(userPageNum%m_numOfEnteries)*4, pTime);
	if(userPageNum == PAGE_FAULT)
	{
		RequestedPage = userPageNum;
		RequestDomain = USER;
		userMiss++;
		return PAGE_FAULT;
	}
	return userPageNum;
}

void MemoryManagementUnit::replaceOuter(int pid, int page, int addr)
{
	(*m_outerTables)[pid][page] = addr;
}

void MemoryManagementUnit::printTable()
{
	cout << "Current Outer Table" << endl;
	for(int i=0; i<(m_pageSize/4); i++)
	{
		cout << "(" << i << " , ";

		if(m_currOuterTable[i] == -1)
			cout << "---";
		else
			cout << (m_pageSize * m_currOuterTable[i]);
		
		cout << ")" << endl;
	}
}

double MemoryManagementUnit::getUserHitRate()
{
	double userHit = userTotal - userMiss;
	return userHit / userTotal;
}

double MemoryManagementUnit::getKernelHitRate()
{
	double kernelHit = kernelTotal - kernelMiss;
	return kernelHit / kernelTotal;
}
